import * as THREE from 'three';
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';

// 定义矩形区域类型
export type LatLngRect = {
  minLat: number;
  maxLat: number;
  minLng: number;
  maxLng: number;
};

// 多边形类型
export type LatLngPolygon = {
  points: { lat: number; lng: number }[];
  name?: string;
};

// 经纬度归一化函数
export function normalizeLng(lng: number) {
  return ((((lng + 180) % 360) + 360) % 360) - 180;
}

// 经纬度转球面坐标
export function latLngToXYZ(lat: number, lng: number, radius = 1) {
  lng = normalizeLng(lng);
  const phi = (90 - lat) * (Math.PI / 180);
  const theta = -lng * (Math.PI / 180); // 修正：加负号，保证和点击方向一致
  const x = radius * Math.sin(phi) * Math.cos(theta);
  const z = radius * Math.sin(phi) * Math.sin(theta);
  const y = radius * Math.cos(phi);
  return new THREE.Vector3(x, y, z);
}

// 矩形转多边形工具
export function rectToPolygon(rect: LatLngRect, step = 2): LatLngPolygon {
  const { minLat, maxLat, minLng, maxLng, name } = rect;
  const points: { lat: number; lng: number }[] = [];
  // 南边
  for (let lng = minLng; lng < maxLng; lng += step) points.push({ lat: minLat, lng: normalizeLng(lng) });
  points.push({ lat: minLat, lng: normalizeLng(maxLng) });
  // 东边
  for (let lat = minLat; lat < maxLat; lat += step) points.push({ lat, lng: normalizeLng(maxLng) });
  points.push({ lat: maxLat, lng: normalizeLng(maxLng) });
  // 北边
  for (let lng = maxLng; lng > minLng; lng -= step) points.push({ lat: maxLat, lng: normalizeLng(lng) });
  points.push({ lat: maxLat, lng: normalizeLng(minLng) });
  // 西边
  for (let lat = maxLat; lat > minLat; lat -= step) points.push({ lat, lng: normalizeLng(minLng) });
  // 闭合
  points.push({ lat: minLat, lng: normalizeLng(minLng) });
  return { points, name };
}

// 球面矩形边界采样函数
export function getRectBorderPoints(rect: LatLngRect, step = 2): THREE.Vector3[] {
  const { minLat, maxLat, minLng, maxLng } = rect;
  const points: THREE.Vector3[] = [];
  // 南边
  for (let lng = minLng; lng < maxLng; lng += step) {
    points.push(latLngToXYZ(minLat, lng, 1.01));
  }
  points.push(latLngToXYZ(minLat, maxLng, 1.01));
  // 东边
  for (let lat = minLat; lat < maxLat; lat += step) {
    points.push(latLngToXYZ(lat, maxLng, 1.01));
  }
  points.push(latLngToXYZ(maxLat, maxLng, 1.01));
  // 北边
  for (let lng = maxLng; lng > minLng; lng -= step) {
    points.push(latLngToXYZ(maxLat, lng, 1.01));
  }
  points.push(latLngToXYZ(maxLat, minLng, 1.01));
  // 西边
  for (let lat = maxLat; lat > minLat; lat -= step) {
    points.push(latLngToXYZ(lat, minLng, 1.01));
  }
  // 闭合
  points.push(latLngToXYZ(minLat, minLng, 1.01));
  return points;
}

// 计算经度最小弧长（考虑跨±180°）
function getLngSpan(lng1: number, lng2: number) {
  const d = Math.abs(lng1 - lng2);
  return d > 180 ? 360 - d : d;
}

// 计算正确的经度范围，处理跨越-180到180度的情况
export function getCorrectLngRange(lng1: number, lng2: number): { minLng: number; maxLng: number } {
  // 归一化经度到-180到180范围
  const normalizeLng = (lng: number) => {
    return ((((lng + 180) % 360) + 360) % 360) - 180;
  };

  const n1 = normalizeLng(lng1);
  const n2 = normalizeLng(lng2);

  // 计算两个可能的区间
  const span1 = Math.abs(n1 - n2);
  const span2 = 360 - span1;

  // 选择较小的区间（从左到右小于180度的区间）
  if (span1 <= span2) {
    return {
      minLng: Math.min(n1, n2),
      maxLng: Math.max(n1, n2)
    };
  } else {
    // 跨越-180/180度的情况
    if (n1 > n2) {
      return {
        minLng: n1,
        maxLng: n2 + 360
      };
    } else {
      return {
        minLng: n2,
        maxLng: n1 + 360
      };
    }
  }
}

// 判断两个矩形是否相交（参考2D逻辑，处理跨越经线情况）
export function rectIntersects(rect1: LatLngRect, rect2: LatLngRect) {
  // 纬度检查
  if (rect1.maxLat < rect2.minLat || rect1.minLat > rect2.maxLat) {
    return false;
  }

  // 先归一化选区的经度到-180到180范围
  const normalizeLng = (lng: number) => {
    // 先处理大数值，避免浮点数精度问题
    const cycles = Math.floor(lng / 360);
    lng = lng - cycles * 360;

    // 然后归一化到-180到180范围
    while (lng > 180) lng -= 360;
    while (lng < -180) lng += 360;
    return lng;
  };

  const normMinLng = normalizeLng(rect2.minLng);
  const normMaxLng = normalizeLng(rect2.maxLng);

  // 检查是否跨越经线
  const originalSpan = Math.abs(rect2.maxLng - rect2.minLng);
  const isCrossingMeridian = normMinLng > normMaxLng || originalSpan > 180;

  if (!isCrossingMeridian) {
    // 正常情况：没有跨越经线，使用简单的AABB检查
    return !(rect1.maxLng < normMinLng || rect1.minLng > normMaxLng);
  } else {
    // 跨越经线的情况：检查区域是否与选区的任一部分相交
    const intersectsFirstPart = !(rect1.maxLng < normMinLng || rect1.minLng > 180);
    const intersectsSecondPart = !(rect1.maxLng < -180 || rect1.minLng > normMaxLng);

    return intersectsFirstPart || intersectsSecondPart;
  }
}

// 判断polygon与选区是否相交（参考2D逻辑，处理跨越经线情况）
export function polygonIntersectsRect(polygon: LatLngPolygon, rect: LatLngRect) {
  // 先归一化选区的经度到-180到180范围
  const normalizeLng = (lng: number) => {
    // 先处理大数值，避免浮点数精度问题
    const cycles = Math.floor(lng / 360);
    lng = lng - cycles * 360;

    // 然后归一化到-180到180范围
    while (lng > 180) lng -= 360;
    while (lng < -180) lng += 360;
    return lng;
  };

  const normMinLng = normalizeLng(rect.minLng);
  const normMaxLng = normalizeLng(rect.maxLng);

  // 检查是否跨越经线
  const originalSpan = Math.abs(rect.maxLng - rect.minLng);
  const isCrossingMeridian = normMinLng > normMaxLng || originalSpan > 180;

  if (!isCrossingMeridian) {
    // 正常情况：没有跨越经线，使用简单的AABB检查
    return polygon.points.some((pt) => pt.lat >= rect.minLat && pt.lat <= rect.maxLat && pt.lng >= normMinLng && pt.lng <= normMaxLng);
  } else {
    // 跨越经线的情况：检查多边形的点是否与选区的任一部分相交
    return polygon.points.some((pt) => {
      // 纬度检查
      if (pt.lat < rect.minLat || pt.lat > rect.maxLat) {
        return false;
      }

      // 经度检查：点可能在选区的任一部分
      const intersectsFirstPart = pt.lng >= normMinLng && pt.lng <= 180;
      const intersectsSecondPart = pt.lng >= -180 && pt.lng <= normMaxLng;

      return intersectsFirstPart || intersectsSecondPart;
    });
  }
}

// 判断点是否在矩形内（处理跨越经线情况）
export function pointIntersectsRect(point: { lat: number; lng: number }, rect: LatLngRect): boolean {
  // 纬度检查
  if (point.lat < rect.minLat || point.lat > rect.maxLat) {
    return false;
  }

  // 先归一化选区的经度到-180到180范围
  const normalizeLng = (lng: number) => {
    // 先处理大数值，避免浮点数精度问题
    const cycles = Math.floor(lng / 360);
    lng = lng - cycles * 360;

    // 然后归一化到-180到180范围
    while (lng > 180) lng -= 360;
    while (lng < -180) lng += 360;
    return lng;
  };

  const normMinLng = normalizeLng(rect.minLng);
  const normMaxLng = normalizeLng(rect.maxLng);

  // 检查是否跨越经线
  const originalSpan = Math.abs(rect.maxLng - rect.minLng);
  const isCrossingMeridian = normMinLng > normMaxLng || originalSpan > 180;

  if (!isCrossingMeridian) {
    // 正常情况：没有跨越经线，使用简单的AABB检查
    return point.lng >= normMinLng && point.lng <= normMaxLng;
  } else {
    // 跨越经线的情况：点可能在选区的任一部分
    const intersectsFirstPart = point.lng >= normMinLng && point.lng <= 180;
    const intersectsSecondPart = point.lng >= -180 && point.lng <= normMaxLng;

    return intersectsFirstPart || intersectsSecondPart;
  }
}

// 精确计算地球在屏幕上的最大像素直径（采样赤道一圈投影后最大距离）
export function getEarthScreenDiameterPrecise(camera: THREE.PerspectiveCamera, renderer: THREE.WebGLRenderer, samples = 360) {
  const width = renderer.domElement.clientWidth;
  const height = renderer.domElement.clientHeight;
  const points = [];
  for (let i = 0; i < samples; i++) {
    const theta = (i / samples) * 2 * Math.PI;
    // 球面赤道圆上的点
    const v = new THREE.Vector3(Math.cos(theta), 0, Math.sin(theta));
    const p = v.clone().project(camera);
    if (p.z < -1 || p.z > 1) {
      continue; // 跳过NDC范围外的点
    }
    if (!isFinite(p.x) || Math.abs(p.x) > 10) {
      continue;
    }
    points.push({
      x: (p.x * 0.5 + 0.5) * width,
      y: (p.y * -0.5 + 0.5) * height
    });
  }
  // 找到投影后距离最远的两个点
  let maxDist = 0;
  for (let i = 0; i < points.length; i++) {
    for (let j = i + 1; j < points.length; j++) {
      const dx = points[i].x - points[j].x;
      const dy = points[i].y - points[j].y;
      const dist = Math.sqrt(dx * dx + dy * dy);
      if (dist > maxDist) {
        maxDist = dist;
      }
    }
  }

  return maxDist;
}

// 计算NDC点对应的球面交点
export function getSphereIntersection(camera: THREE.PerspectiveCamera, ndcX: number, ndcY: number) {
  const raycaster = new THREE.Raycaster();
  raycaster.setFromCamera(new THREE.Vector2(ndcX, ndcY), camera);
  // 球心在(0,0,0)，半径1
  const origin = raycaster.ray.origin;
  const dir = raycaster.ray.direction;
  // 求射线与球的交点
  // |origin + t*dir|^2 = 1
  const a = dir.dot(dir);
  const b = 2 * origin.dot(dir);
  const c = origin.dot(origin) - 1;
  const discriminant = b * b - 4 * a * c;
  if (discriminant < 0) return null;
  const t1 = (-b - Math.sqrt(discriminant)) / (2 * a);
  const t2 = (-b + Math.sqrt(discriminant)) / (2 * a);
  const t = t1 > 0 ? t1 : t2; // 取最近的正交点
  if (t < 0) return null;
  return origin.clone().add(dir.clone().multiplyScalar(t)).normalize();
}

// 采样屏幕宽度，找到最左和最右有交点的球面点，计算它们的夹角作为visibleArc
export function getVisibleArcBySampling(camera: THREE.PerspectiveCamera, renderer: THREE.WebGLRenderer, step = 2) {
  const width = renderer.domElement.clientWidth;
  const height = renderer.domElement.clientHeight;
  const points = [];
  for (let x = 0; x < width; x += step) {
    // 屏幕坐标转NDC
    const ndcX = (x / width) * 2 - 1;
    const ndcY = 0;
    const raycaster = new THREE.Raycaster();
    raycaster.setFromCamera(new THREE.Vector2(ndcX, ndcY), camera);
    const origin = raycaster.ray.origin;
    const dir = raycaster.ray.direction;
    // 求射线与球面交点
    const a = dir.dot(dir);
    const b = 2 * origin.dot(dir);
    const c = origin.dot(origin) - 1;
    const discriminant = b * b - 4 * a * c;
    if (discriminant < 0) continue;
    const t1 = (-b - Math.sqrt(discriminant)) / (2 * a);
    const t2 = (-b + Math.sqrt(discriminant)) / (2 * a);
    const t = t1 > 0 ? t1 : t2;
    if (t < 0) continue;
    const pt = origin.clone().add(dir.clone().multiplyScalar(t)).normalize();
    points.push(pt);
  }
  if (points.length < 2) return Math.PI; // 兜底
  return points[0].angleTo(points[points.length - 1]);
}

/**
 * 根据鼠标事件获取地球表面交点（经纬度和三维坐标）
 * @param event 鼠标事件
 * @param camera three.js相机
 * @param renderer three.js渲染器
 * @param mesh 地球mesh
 * @returns { lat, lng, point } 或 null
 */
export function getMouseRaycast(
  event: MouseEvent,
  camera: THREE.PerspectiveCamera,
  renderer: THREE.WebGLRenderer,
  mesh: THREE.Mesh
): { lat: number; lng: number; point: THREE.Vector3 } | null {
  const rect = renderer.domElement.getBoundingClientRect();
  const mouse = new THREE.Vector2(((event.clientX - rect.left) / rect.width) * 2 - 1, -((event.clientY - rect.top) / rect.height) * 2 + 1);
  const raycaster = new THREE.Raycaster();
  raycaster.setFromCamera(mouse, camera);
  const intersects = raycaster.intersectObject(mesh, false);
  if (intersects.length > 0) {
    const point = intersects[0].point;
    const RADIUS = 1;
    const EPSILON = 0.015;
    if (Math.abs(point.length() - RADIUS) < EPSILON) {
      const localPoint = mesh.worldToLocal(point.clone());
      const lat = (Math.asin(localPoint.y / RADIUS) * 180) / Math.PI;
      let lng = (-Math.atan2(localPoint.z, localPoint.x) * 180) / Math.PI;
      return {
        lat: Number(lat.toFixed(4)),
        lng: Number(normalizeLng(lng).toFixed(4)),
        point: point.clone()
      };
    }
  }
  return null;
}

/**
 * 获取不规则模型表面交点的“伪经纬度”和三维坐标
 * @param event 鼠标事件
 * @param camera three.js相机
 * @param renderer three.js渲染器
 * @param mesh three.js Mesh或Object3D
 * @returns { lat, lng, point } 或 null
 */
export function getMouseRaycastForModel(
  event: MouseEvent,
  camera: THREE.PerspectiveCamera,
  renderer: THREE.WebGLRenderer,
  mesh: THREE.Object3D
): { lat: number; lng: number; point: THREE.Vector3 } | null {
  const rect = renderer.domElement.getBoundingClientRect();
  const mouse = new THREE.Vector2(((event.clientX - rect.left) / rect.width) * 2 - 1, -((event.clientY - rect.top) / rect.height) * 2 + 1);
  const raycaster = new THREE.Raycaster();
  raycaster.setFromCamera(mouse, camera);
  const intersects = raycaster.intersectObject(mesh, false);
  if (intersects.length > 0) {
    const point = intersects[0].point;
    const localPoint = mesh.worldToLocal(point.clone());
    const len = localPoint.length();
    if (len === 0) {
      return { lat: NaN, lng: NaN, point: point.clone() };
    }
    // 归一化localPoint，始终反算伪经纬度
    const nx = localPoint.x / len;
    const ny = localPoint.y / len;
    const nz = localPoint.z / len;
    const lat = (Math.asin(ny) * 180) / Math.PI;
    let lng = (-Math.atan2(nz, nx) * 180) / Math.PI;
    return {
      lat: Number(lat.toFixed(4)),
      lng: Number(normalizeLng(lng).toFixed(4)),
      point: point.clone()
    };
  }
  return null;
}

/**
 * 创建多边形线框
 * @param points THREE.Vector3[]
 * @param color 线颜色
 * @returns THREE.Line
 */
export function createLine(points: THREE.Vector3[], color: number): THREE.Line {
  if (points.length > 0) {
    points = [...points, points[0]]; // 闭合
  }
  const geometry = new THREE.BufferGeometry().setFromPoints(points);
  const material = new THREE.LineBasicMaterial({ color });
  return new THREE.Line(geometry, material);
}

/**
 * 清理线框对象
 * @param lines 线对象数组
 * @param parent 父对象
 */
export function clearLines(lines: THREE.Line[], parent: THREE.Object3D) {
  lines.forEach((line) => {
    parent.remove(line);
    line.geometry.dispose();
    if (Array.isArray(line.material)) {
      line.material.forEach((m) => m.dispose());
    } else {
      line.material.dispose();
    }
  });
  lines.length = 0;
}

/**
 * 创建地球表面marker（圆形）
 * @param pos THREE.Vector3 位置
 * @param camera 相机
 * @param renderer 渲染器
 * @param color 颜色
 * @param pixelSize 直径像素
 * @returns THREE.Mesh
 */
export function createMarker(
  pos: THREE.Vector3,
  camera: THREE.PerspectiveCamera,
  renderer: THREE.WebGLRenderer,
  color = 0xffff00,
  pixelSize = 10
): THREE.Mesh {
  // 计算物体到相机距离，确定实际半径
  const distance = pos.distanceTo(camera.position);
  const fovRad = (camera.fov * Math.PI) / 180;
  const canvasHeightPx = renderer.domElement.height;
  const visibleHeight = 2 * distance * Math.tan(fovRad / 2);
  const unitPerPixel = visibleHeight / canvasHeightPx;
  const radius = (pixelSize / 2) * unitPerPixel;
  const geometry = new THREE.CircleGeometry(radius, 32);
  const material = new THREE.MeshBasicMaterial({ color, transparent: true, opacity: 0.8, side: THREE.DoubleSide });
  const circle = new THREE.Mesh(geometry, material);
  circle.position.copy(pos);
  circle.lookAt(new THREE.Vector3(0, 0, 0));
  return circle;
}

/**
 * 清理marker对象
 * @param markers marker对象数组
 * @param parent 父对象
 */
export function clearMarkers(markers: THREE.Mesh[], parent: THREE.Object3D) {
  markers.forEach((marker) => {
    parent.remove(marker);
    marker.geometry.dispose();
    if (Array.isArray(marker.material)) {
      marker.material.forEach((m) => m.dispose());
    } else {
      marker.material.dispose();
    }
  });
  markers.length = 0;
}

/**
 * 初始化地球Three.js场景（scene、camera、renderer、earthMesh）
 * @param options.width 画布宽度
 * @param options.height 画布高度
 * @param options.earthImg 地球贴图（必填）
 * @param options.modelUrl 3D模型文件URL（可选，优先级高于球体）
 * @param options.onModelLoaded 模型加载完成回调（可选）
 * @returns { scene, camera, renderer, earthMesh }
 */
export function initEarthScene(options: {
  width: number;
  height: number;
  modelUrl?: string;
  onModelLoaded?: (mesh: THREE.Object3D) => void;
}): {
  scene: THREE.Scene;
  camera: THREE.PerspectiveCamera;
  renderer: THREE.WebGLRenderer;
  earthMesh: THREE.Object3D | null;
} {
  const { width, height, modelUrl, onModelLoaded } = options;
  const scene = new THREE.Scene();
  scene.background = new THREE.Color(0x000000);
  const camera = new THREE.PerspectiveCamera(75, width / height, 0.01, 2000);

  // 计算合适的相机Z位置，让地球直径比容器宽高小20px
  const earthDiameter = 2; // 地球直径（单位球）
  const targetScreenDiameter = Math.min(width, height); // 目标屏幕直径
  // 使用简单的比例关系：cameraZ与屏幕大小成反比
  const cameraZ = (earthDiameter * height) / targetScreenDiameter;

  camera.position.z = cameraZ;
  camera.lookAt(0, 0, 0);
  camera.updateMatrixWorld();
  const renderer = new THREE.WebGLRenderer({ antialias: true });
  renderer.setSize(width, height);
  renderer.setPixelRatio(window.devicePixelRatio);

  let earthMesh: THREE.Object3D | null = null;
  if (modelUrl) {
    // 2. 加载模型
    const loader = new GLTFLoader();
    loader.load(modelUrl, (gltf) => {
      // const model = gltf.scene.children[0];
      const model = gltf.scene.children[0];
      console.log(model);

      // 递归获取所有mesh，合并全局包围盒
      function getAllMeshes(obj) {
        const meshes = [];
        obj.traverse((child) => {
          if (child.isMesh) meshes.push(child);
        });
        return meshes;
      }
      const meshes = getAllMeshes(model);
      const globalBox = new THREE.Box3();
      meshes.forEach((mesh) => globalBox.expandByObject(mesh));
      const center = new THREE.Vector3();
      globalBox.getCenter(center);
      const size = new THREE.Vector3();
      globalBox.getSize(size);
      const radius = Math.max(size.x, size.y, size.z) / 2;
      // 对整个model做居中和缩放
      model.position.sub(center);
      let scale = 1;
      console.log(radius);
      if (radius > 0) {
        scale = 1 / radius;
        model.scale.set(scale, scale, scale);
      }
      model.updateMatrixWorld(true);
      // 打印归一化前后信息
      console.log('全局包围盒中心:', center);
      console.log('全局包围盒尺寸:', size);
      console.log('归一化缩放因子:', scale);
      console.log('归一化后模型缩放:', model.scale);
      console.log('归一化后模型位置:', model.position);
      const boxAfter = new THREE.Box3().setFromObject(model);
      const sizeAfter = new THREE.Vector3();
      boxAfter.getSize(sizeAfter);
      console.log('归一化后包围盒尺寸:', sizeAfter);
      // 可视化包围盒
      const boxHelper = new THREE.Box3Helper(globalBox, 0xff0000);
      scene.add(boxHelper);
      // 添加单位球体wireframe用于可视化对比
      const debugSphere = new THREE.Mesh(
        new THREE.SphereGeometry(1, 32, 32),
        new THREE.MeshBasicMaterial({ color: 0x00ff00, wireframe: true })
      );
      scene.add(debugSphere);

      // 如果没有UV，自动生成球体UV
      if (!model.geometry.attributes.uv) {
        function generateSphereUVs(geometry: THREE.BufferGeometry) {
          const pos = geometry.attributes.position;
          const uvArray = [];
          for (let i = 0; i < pos.count; i++) {
            const x = pos.getX(i);
            const y = pos.getY(i);
            const z = pos.getZ(i);
            // 归一化到单位球
            const len = Math.sqrt(x * x + y * y + z * z);
            const nx = x / len;
            const ny = y / len;
            const nz = z / len;
            // 计算球体UV
            const u = 0.5 + Math.atan2(nz, nx) / (2 * Math.PI);
            const v = 0.5 - Math.asin(ny) / Math.PI;
            uvArray.push(u, v);
          }
          geometry.setAttribute('uv', new THREE.Float32BufferAttribute(uvArray, 2));
        }
        generateSphereUVs(model.geometry);
      }

      model.material = new THREE.MeshStandardMaterial({
        side: THREE.FrontSide
      });
      // 位置和缩放已自动处理，无需再 set(0,0,0) 和 set(1,1,1)
      scene.add(model);
      earthMesh = model;
      if (onModelLoaded) {
        onModelLoaded(model);
      }
    });
  } else {
    // 原有地球体
    const geometry = new THREE.SphereGeometry(1, 256, 256);
    const material = new THREE.MeshStandardMaterial({
      side: THREE.FrontSide,
      roughness: 1.0, // 表面粗糙度高，不反光
      metalness: 0.0
    });
    earthMesh = new THREE.Mesh(geometry, material);
    // 设置地球默认朝向经度0度（格林威治子午线）
    earthMesh.rotation.x = 0;
    earthMesh.rotation.y = -Math.PI / 2; // -90度，让地球朝向经度0度
    scene.add(earthMesh);
  }

  // 灯光
  const ambientLight = new THREE.AmbientLight(0xffffff, 0.6);
  scene.add(ambientLight);
  const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8);
  directionalLight.position.set(5, 3, 5);
  scene.add(directionalLight);

  return { scene, camera, renderer, earthMesh };
}

/**
 * 获取Object3D下所有Mesh
 */
export function getAllMeshes(obj: THREE.Object3D): THREE.Mesh[] {
  const meshes: THREE.Mesh[] = [];
  obj.traverse((child) => {
    if ((child as THREE.Mesh).isMesh) {
      meshes.push(child as THREE.Mesh);
    }
  });
  return meshes;
}

/**
 * 将经纬度点投影到任意不规则模型表面（适用于地形、异形体等）
 * @param lat 纬度
 * @param lng 经度
 * @param mesh THREE.MeslatLngToModelSurfaceh
 * @returns THREE.Vector3 投影点坐标（紧贴模型表面）
 */
export function latLngToModelSurface(lat: number, lng: number, mesh: THREE.Mesh): THREE.Vector3 {
  // 模型已被缩放到半径1，原点为球心
  const pivot = mesh.localToWorld(new THREE.Vector3(0, 0, 0));
  const localRayOrigin = latLngToXYZ(lat, lng, 5); // 半径2，确保在模型外部
  const rayOrigin = mesh.localToWorld(localRayOrigin);
  const dir = pivot.clone().sub(rayOrigin).normalize();

  const raycaster = new THREE.Raycaster(rayOrigin, dir);
  const intersects = raycaster.intersectObject(mesh, false);

  console.log('intersects', intersects);
  if (intersects.length > 0) {
    const hit = intersects[0];
    let normal = hit.face?.normal?.clone() ?? new THREE.Vector3(0, 0, 1);
    normal.transformDirection(mesh.matrixWorld);
    normal.normalize();
    return hit.point.clone().add(normal.multiplyScalar(0.001));
  } else {
    return rayOrigin;
  }
}
